# Create your views here.
from django.http import HttpResponse
from django.shortcuts import render_to_response
from django.views.decorators.http import require_http_methods
from django.core.files.base import ContentFile
from constants import ErrorCode
from models import SocialAnimal
from Utils import utc_now
from django.db.models import Q
from provider.oauth2.models import AccessToken

import django.contrib.auth as d_auth
import json
import re

# valid params we can acception from user
# and these params are allowed for updating
_valid_optional_fields = (
    'picture', 'birthday', 'sex', 'description',
    'city',
)


def _update_user_profile(user, params):
    # check if there are more information given, if true, update
    # those information
    for param in _valid_optional_fields:
        value = params.get(param, '')
        if not value:
            continue

        # only male and female is allowed for sex
        if param == 'sex':
            if value not in ['male', 'female']:
                continue
        
        # save image, default file is limited to 2.5M
        # TODO : wrap this to a function or a class
        if param == 'picture':
            import base64
            import hashlib
            import Image
            import StringIO

            pic = base64.decodestring(value)
            pic_md5 = hashlib.md5(value)

            image = Image.open(StringIO.StringIO(pic))
            pic_filename = pic_md5.hexdigest() + '.' + image.format.lower()

            # check if user already has a avatar
            if user.avatar:
                # delete the exist one
                user.avatar.delete()

            # If save is True, the model's save() method 
            # will be called once the file is saved. 
            user.avatar.save(pic_filename, ContentFile(pic), save=False)
            # we are done with avatar
            continue

        setattr(user, param, value)

    # save user's updated information
    user.save()


# This decorator marks a view as being exempt from the protection 
# ensured by the middleware. 
# https://docs.djangoproject.com/en/dev/ref/contrib/csrf/#how-to-use-it
# TODO : this csrf_exempt should be removed, otherwise, we are open api
# provider, every girl can create her account using this, and we may 
# should care about cross site attack(for mobile app, is that true?)
def register(request):
    # password username and email are must be given fields
    email = request.POST.get('email', '')
    username = request.POST.get('username', '')
    # get password from request
    password = request.POST.get('password', '')
    if not (email and username and password):
        error_code = {'code': hex(ErrorCode.BAD_REQUEST_DATA)}
        return HttpResponse(json.dumps(error_code))
        
    # TODO : django Auth_user require username when creating a new user
    # but per our requirement, the email address should be sufficient
    # as a workaround: grap the chars before@ as the username
    #if not username_in:
    #    email_prefix_pattern = re.compile('([\w\-\.]+)@')
    #    email_prefix = email_prefix_pattern.findall(email_in)[0]

    try:
        # check if the email or username is already been used 
        # silly workaround, but the email username for now should
        # both be unique
        is_user_exist = SocialAnimal.objects.get(
            Q(username=username) | Q(email=email)
        )
    except SocialAnimal.DoesNotExist:
        is_user_exist = None

    if is_user_exist:
        error_code = {'code': hex(ErrorCode.USER_EXIST)}
        return HttpResponse(json.dumps(error_code))

    # create a new user
    new_user = SocialAnimal.objects.create_user(
        username,
        email=email,
        password=password,
    )
    new_user.save()

    # set user's additional information
    _update_user_profile(new_user, request.POST)

    # return value should include the error code and user id
    resp = {
        'code' : hex(ErrorCode.CREATE_USRE_SUCCESS), 
        'userid' : new_user.id
    }

    return HttpResponse(json.dumps(resp))


def login(request):
    # use email and password to login
    password = request.POST.get('password', '')
    username = request.POST.get('username', '')
    email = request.POST.get('email', '')

    email_or_username = username if username else email

    ''' NOTE: Calling authenticate() first
        When you're manually logging a user in, you must call 
        authenticate() before you call login(). authenticate() 
        sets an attribute on the User noting which authentication 
        backend successfully authenticated that user (see the 
        backends documentation for details), and this information
        is needed later during the login process.
    '''
    # this authenticate will call our own auth_back method
    # SocialAnimalBackend.authenticate, so here we pass email
    # as username to authenticate
    user = d_auth.authenticate(username=email_or_username, password=password)

    if user is not None:
        if user.is_active:
            # user is active, so login him, login will store
            # session id in db, the session cookie stay valid
            # for two weeks, this time can be changed in settings.py
            # SESSION_COOKIE_AGE(seconds)
            d_auth.login(request, user)
            error_code = {'code': hex(ErrorCode.USER_LOGIN_SUCCESS)}
            return HttpResponse(json.dumps(error_code))
        else:
            # Return a 'disabled account' error message
            error_code = {'code': hex(ErrorCode.USER_DISABLED)}
            return HttpResponse(json.dumps(error_code))
    else:
        # Return an 'invalid login' error message.
        error_code = {'code': hex(ErrorCode.USER_PW_OR_NAME_ERROR)}
        return HttpResponse(json.dumps(error_code))

# expire access token
# TODO : move this out of views.py
def expire_access_token(access_token=None):
    try:
        access_token = AccessToken.objects.get(token=access_token)
        access_token.expires = utc_now()
        access_token.save()
    except AccessToken.DoesNotExist:
        pass

def logout(request):
    expire_access_token(request.POST.get('access_token', ''))
    error_code = {'code': hex(ErrorCode.USER_LOGOUT_SUCCESS)}
    return HttpResponse(json.dumps(error_code))


def update(request):
    is_authorized_user = d_auth.authenticate(access_token=request.POST.get('access_token', ''))

    if is_authorized_user:
        # user has logged in
        _update_user_profile(is_authorized_user, request.POST)

        # TODO : 
        # 1, check if update is really successful
        # 2, check if the given filed are legal for updating
        error_code = {'code': hex(ErrorCode.USER_UPDATE_SUCCESS)}
        return HttpResponse(json.dumps(error_code))
    else:
        # user hasn't logged in yet, return 403 forbidden
        error_code = {'code': hex(ErrorCode.LOGIN_REQUIRED)}
        return HttpResponse(json.dumps(error_code))
